# -*- coding: utf-8 -*-
# @Time    : 2021/3/16 14:44
# @Author  : huangwei
# @File    : signature.py
# @Software: PyCharm
import cv2
import numpy as np
from table_method import get_equation, point_line


def line_function( lines ):
    """ 去除与大多数线不平行的线 """
    num_lines = len(lines)

    new_lines = []
    tan_list = []
    for line in lines:
        x1, y1, x2, y2 = line
        dy = y2 - y1
        dx = x2 - x1
        if dx != 0:
            tan = dy / dx
        else:
            tan = 100
        tan_list.append(tan)

    tan_sort = sorted(tan_list)
    mid_tan = tan_sort[int(num_lines / 2)]

    for i in range(num_lines):
        if abs(mid_tan - tan_sort[i]) < 0.1:
            new_lines.append(lines[i])

    return new_lines


def sort_line( lines ):
    # 对传入的线段根据中点 Y 值的大小进行排序
    center_y = []
    for line in lines:
        x1, y1, x2, y2 = line
        cy = (y1 + y2) / 2
        center_y.append(cy)

    center_y = np.array(center_y)
    sorted_index = np.argsort(center_y)

    lines = np.array(lines)
    lines = lines[sorted_index]
    lines = lines.tolist()

    return lines


def sort_box_to_group( boxes, det_boxes, lines ):
    """ 将boxes进行分组"""
    # 首先将lines中与大多数不平行的线去掉，再从上到下进行排序
    new_lines = line_function(lines)
    new_lines = sort_line(new_lines)

    # 依次取两条线，再找到再这两条线之间的box
    num_lines = len(new_lines)

    sort_box_list = []
    sort_det_box_list = []
    for i in range(num_lines - 1):
        one_list = []
        one_det_list = []
        # 这条线和下一条线的一般方程式
        a1, b1, c1 = get_equation(new_lines[i][:2], new_lines[i][2:])
        a2, b2, c2 = get_equation(new_lines[i + 1][:2], new_lines[i + 1][2:])

        # 轮流代入box中的坐标判断是否在两条线之间
        for box in boxes:
            x1, y1, x2, y2, x3, y3, x4, y4 = box
            cx, cy = int((x1 + x2 + x3 + x4) / 4), int((y1 + y2 + y3 + y4) / 4)
            flag1 = point_line((cx, cy), a1, b1, c1)
            flag2 = point_line((cx, cy), a2, b2, c2)

            # 一个大于 0 一个小于 0 则符合在两条直线之间
            if flag1 * flag2 < 0:
                one_list.append(box)

        sort_box_list.append(one_list)

        # 同理对 det_box进行相同操作
        for box in det_boxes:
            p1, p2, p3, p4 = box
            cx, cy = int((p1[0] + p2[0] + p3[0] + p4[0]) / 4), int((p1[1] + p2[1] + p3[1] + p4[1]) / 4)
            flag1 = point_line((cx, cy), a1, b1, c1)
            flag2 = point_line((cx, cy), a2, b2, c2)

            # 一个大于 0 一个小于 0 则符合在两条直线之间
            if flag1 * flag2 < 0:
                one_det_list.append(box)

        sort_det_box_list.append(one_det_list)

    return sort_box_list, sort_det_box_list


def get_center_point( points ):
    """ 传入四个点求中点"""
    x = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4
    y = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4

    return x, y


def word_and_box( box, det_boxes ):
    x1, y1, x2, y2, x3, y3, x4, y4 = box
    x_list = [x1, x2, x3, x4]
    y_list = [y1, y2, y3, y4]
    x_min, x_max, y_min, y_max = np.min(x_list), np.max(x_list), np.min(y_list), np.max(y_list)

    box_list = []
    for det_box in det_boxes:
        center_x, center_y = get_center_point(det_box)
        if x_min < center_x < x_max and y_min < center_y < y_max:
            box_list.append(det_box)

    return box_list


def get_rotate_crop_image( img, points ):
    """
    旋转切割图片
    img_height, img_width = img.shape[0:2]
    left = int(np.min(points[:, 0]))
    right = int(np.max(points[:, 0]))
    top = int(np.min(points[:, 1]))
    bottom = int(np.max(points[:, 1]))
    img_crop = img[top:bottom, left:right, :].copy()
    points[:, 0] = points[:, 0] - left
    points[:, 1] = points[:, 1] - top
    """
    img_crop_width = int(
        max(
            np.linalg.norm(points[0] - points[1]),
            np.linalg.norm(points[2] - points[3])))
    img_crop_height = int(
        max(
            np.linalg.norm(points[0] - points[3]),
            np.linalg.norm(points[1] - points[2])))
    pts_std = np.float32([[0, 0], [img_crop_width, 0],
                          [img_crop_width, img_crop_height],
                          [0, img_crop_height]])
    M = cv2.getPerspectiveTransform(points, pts_std)
    dst_img = cv2.warpPerspective(
        img,
        M, (img_crop_width, img_crop_height),
        borderMode=cv2.BORDER_REPLICATE,
        flags=cv2.INTER_CUBIC)
    dst_img_height, dst_img_width = dst_img.shape[0:2]
    if dst_img_height * 1.0 / dst_img_width >= 1.5:
        dst_img = np.rot90(dst_img)
    return dst_img


def img2trans( img_path, save_path ):
    """图片转为透明"""
    img = cv2.imread(img_path)
    shape = img.shape[0:2]

    # 先将其二值化用来找空白处坐标
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, bin_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)  # 将大于170的像素点转为255

    # 将图片转为4通道，添加一个透明通道
    img_a = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)

    # 依次扫描每一个像素点，将其二值图中为255的位置的值改为 (0, 0, 0, 0)
    # 将图像边缘改为透明的
    for h in range(shape[0]):
        for w in range(shape[1]):
            if 5 < h < shape[0] - 5 and 10 < w < shape[1] - 10:
                if bin_img[h][w] == 255:
                    img_a[h][w] = [255, 255, 255, 0]
            else:
                img_a[h][w] = [255, 255, 255, 0]

    # cv2.imwrite(save_path, img_a)
    # 保存文件名带中文名
    cv2.imencode('.png', img_a)[1].tofile(save_path)


def cut_name( img_path, boxes, det_boxes, output_path, index, text_recognizer, cols ):
    """ 将传入的每一行的点的坐标将签名截取 """
    if len(boxes) == 0:
        return

    if len(cols) != len(boxes):
        return

    img = cv2.imread(img_path)

    # 对box进行从左到右排序
    center_x = []
    for box in boxes:
        x1, y1, x2, y2, x3, y3, x4, y4 = box
        cx = (x1 + x2 + x3 + x4) / 4
        center_x.append(cx)

    center_x = np.array(center_x)
    sort_index = np.argsort(center_x)

    boxes = np.array(boxes)
    boxes = boxes[sort_index]
    boxes = boxes.tolist()

    if cols[0] == 'name':
        box1 = boxes[0]
    elif cols[1] == 'name':
        box1 = boxes[1]
    else:
        box1 = boxes[2]

    # 检测该box文字作为文件名，检测不到文字则return空
    temp_list1 = word_and_box(box1, det_boxes)
    if len(temp_list1) != 0:
        crop_list = []
        img_crop = get_rotate_crop_image(img, temp_list1[0])
        crop_list.append(img_crop)

        rec_res = text_recognizer(crop_list)
        name = rec_res[0][0]
        if name == '姓名':
            return
    else:
        return "no name"

    output_filepath = "%s/%s_signature.png" % (output_path, name)

    if cols[2] == 'signature':
        box2 = boxes[2]
    else:
        box2 = boxes[3]

    temp_list4 = word_and_box(box2, det_boxes)
    if len(temp_list4) != 0:
        # 裁剪出box
        x1, y1, x2, y2, x3, y3, x4, y4 = box2
        points = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
        points = np.array(points, dtype=np.float32)

        crop_img = get_rotate_crop_image(img, points)
        temp_crop_path = "./temp_path/temp_%d.png" % index
        cv2.imwrite(temp_crop_path, crop_img)

        # 将提取出的签名转换为透明的
        img2trans(temp_crop_path, output_filepath)
    else:
        return "no signature in this box"
